home *** CD-ROM | disk | FTP | other *** search
/ 9-Digit Zip Code Directory / 9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO / z4src.zip / DIINDEX.C < prev    next >
C/C++ Source or Header  |  1993-07-29  |  12KB  |  408 lines

  1. //----------------------------------------------------------------------------
  2. //                            MODULE DESCRIPTION
  3. //
  4. //  Module:    diisam.c
  5. //   Title:    Data File I/O Library
  6. //  Notice:    John M. Weeder
  7. //                 Copyright (c) 1993. All rights reserved.
  8. //             This module contains proprietary information and should be 
  9. //                treated as confidential.
  10. //
  11. //----------------------------------------------------------------------------
  12. //                           MAINTENANCE HISTORY
  13. //
  14. // $Workfile$
  15. // $Revision$
  16. //   $Author$
  17. //     $Date$
  18. //      $Log$    
  19. //
  20. //----------------------------------------------------------------------------
  21. //                             MODULE NARRATIVE
  22. //
  23. //
  24. //    This module contains to generate an ISAM index file.
  25. //
  26. //    THIS MODULE IS NOT RE-ENTRANT.
  27. //
  28. //    The code in this module should be written entirely in C. 
  29. //    Do not use any C++ constructs.
  30. //
  31. //    This module is portable to:
  32. //        DOS 3.X+
  33. //        MS Windows 3.X+
  34. //        OS/2 2.X+
  35. //        OS/2 2.0 PM
  36. //        SCO UNIX.
  37. //
  38. //    The following compilers are supported:
  39. //        MSC 6.0A
  40. //        MSC/C++ 7.0
  41. //        Borland C++ 3.1 for DOS
  42. //        Borland C++ 1.0 for OS/2 2.X
  43. //        SCO UNIX cc
  44. //
  45. //----------------------------------------------------------------------------
  46. #include <di.h>
  47.  
  48.  
  49. //----------------------------------------------------------------------------
  50. //    Globals
  51. //----------------------------------------------------------------------------
  52. typedef struct GI                                // Global data
  53. {
  54.     HPF hpf;                                        // Physical file handle
  55.     USHORT usBlockSize;                        // Block size of index
  56.    USHORT usBlockUsed;                        // Amount of current block used
  57.    LONG lBlocks;                                // Blocks in this logical file
  58.    PCSZ pcszLogical;                            // Logical file name
  59.    PFNINDEX pfnindex;                        // User index function
  60.    PBYTE pbBlock;                                // Pointer to block
  61.    LONG lTotalBlocks;                        // Total blocks
  62.    LONG lTotalSlack;                            // Total slack space
  63.    FPOS fpos;                                    // Current file position
  64.    HF hf;                                        // Output file handle
  65.     DI_INDEX di_index;
  66. } GI;
  67. static GI gi;
  68.  
  69.  
  70. //----------------------------------------------------------------------------
  71. //    Prototypes
  72. //----------------------------------------------------------------------------
  73. static BOOL FN_L DioIndexBase(void);
  74. static BOOL FN_L DioIndexDelete(void);
  75. static BOOL FN_L DioIndexLevel(USHORT);
  76. static BOOL FN_L DioIndexWrite(void);
  77.  
  78.  
  79. //----------------------------------------------------------------------------
  80. //   Description:    Create a multi-level ISAM index
  81. //    Parameters:    pcsz                Physical file name. 
  82. //                                            File is opened, then closed when indexing is
  83. //                                            complete.
  84. //                        pcszLogical        Logical file to index
  85. //                        pfnindex            Indexing function
  86. //                        cBlockSize        Size of index block.
  87. //                                            If 0, use default size
  88. //       Returns:    TRUE if successful.
  89. //----------------------------------------------------------------------------
  90. BOOL FN_E DioIndex(PCSZ pcsz, PCSZ pcszLogical, PFNINDEX pfnindex, USHORT usBlockSize)
  91. {
  92.     BOOL fResult = FALSE;
  93.     USHORT usLevel = 0;
  94.  
  95.     Assert(pcsz);                                // Validate data
  96.     Assert(pcszLogical);                    
  97.     Assert(pfnindex);
  98.  
  99.     memset(&gi, 0, sizeof(gi));            // Set up global variables
  100.     gi.usBlockSize = usBlockSize >= sizeof(ISAMENTRY) ? usBlockSize: ISAM_BLOCK_SIZE;
  101.     gi.pcszLogical = pcszLogical;
  102.     gi.pfnindex = pfnindex;
  103.  
  104.     Output(                                        // Display information
  105.         "Indexing:\n"
  106.         "  Physical file: %s\n"
  107.         "   Logical file: %s\n",
  108.         pcsz, pcszLogical);
  109.                                                     // Open physical file for writing
  110.     if (!DioOpenPhysical(pcsz, &gi.hpf, TRUE))
  111.         return FALSE;
  112.                                                       // Delete existing indexes
  113.     if (!DioIndexDelete())    
  114.         goto ERROR_EXIT;
  115.                                                     // Allocate a data buffer
  116.     gi.pbBlock    = MemAlloc(gi.usBlockSize);    
  117.     if (gi.pbBlock == NULL)
  118.         goto ERROR_EXIT;
  119.                                                     
  120.     if (!DioIndexBase())                        // Index data file
  121.         goto ERROR_EXIT;
  122.  
  123.     while (gi.lBlocks > 1)                    // Index until Top level is a single
  124.         {                                            //  block
  125.         usLevel++;
  126.         Assert(usLevel < ISAM_MAX_LEVEL);
  127.         if (!DioIndexLevel(usLevel))
  128.             goto ERROR_EXIT;
  129.         }
  130.     Output(
  131.         "Indexing complete.\n"
  132.         "  %u levels.\n"
  133.         "  %ld blocks totaling %ld (%u K) bytes.\n"
  134.         "  %ld slack bytes (%u %%).\n"
  135.         "\n",
  136.         usLevel + 1,
  137.         gi.lTotalBlocks,
  138.         gi.lTotalBlocks * (LONG)gi.usBlockSize,
  139.         K(gi.lTotalBlocks * (LONG)gi.usBlockSize),
  140.         gi.lTotalSlack,
  141.         PERCENT(gi.lTotalSlack, gi.lTotalBlocks * (LONG)gi.usBlockSize));
  142.     fResult = TRUE;
  143.  
  144. ERROR_EXIT:
  145.     if (gi.pbBlock)                                // Free buffer
  146.         MemFree(gi.pbBlock);
  147.     DioClosePhysical(gi.hpf);                // Close physical file
  148.     return fResult;
  149. }
  150.  
  151.  
  152. //----------------------------------------------------------------------------
  153. //   Description:    Index the first level of the isam data file.
  154. //    Parameters:
  155. //       Returns:    TRUE if successful.
  156. //----------------------------------------------------------------------------
  157. static BOOL FN_L DioIndexBase(void)
  158. {
  159.     HLF hlf;
  160.     LONG i, lDataBlocks;
  161.     USHORT usDataBlockSize;
  162.     ISAMENTRY entry;
  163.     USHORT usKeyTotal;
  164.     BOOL fResult = FALSE;
  165.     BOOL fUserInit = FALSE;
  166.     PBYTE pbData = NULL;
  167.                                                     // Open logical file
  168.     if (!DioOpenLogical(gi.pcszLogical, &hlf, DFT_ISAM_DATA))
  169.         return FALSE;
  170.                                                     // Get block size and number of blocks
  171.     if (!DioGetBlockSize(hlf, &usDataBlockSize))
  172.         goto ERROR_EXIT;
  173.  
  174.     pbData = MemAlloc((SIZET)usDataBlockSize);    
  175.     if (pbData == NULL)
  176.         goto ERROR_EXIT;
  177.  
  178.     if (!DioGetBlocks(hlf, &lDataBlocks))
  179.         goto ERROR_EXIT;
  180.  
  181.     Output(
  182.         "Indexing base data file.\n"
  183.         "  Block Size: %u\n"
  184.         "  Total Blocks: %ld\n",
  185.         usDataBlockSize, lDataBlocks);
  186.                                                     // Allocate data buffer
  187.                                                     // Set up to append isam data
  188.     if (!DioAppend(HPF2PCSZ(gi.hpf), gi.pcszLogical, DFT_ISAM0,
  189.     gi.usBlockSize, &gi.hf, NULL))
  190.         goto ERROR_EXIT;
  191.  
  192.     gi.fpos = FileGetPos(gi.hf);            // Store position to append at
  193.     if (gi.fpos < 0)
  194.         goto ERROR_EXIT;
  195.                                                     // Allow user to initialize
  196.     gi.di_index.lBlock = ISAM_START;
  197.     if (gi.pfnindex(&gi.di_index) == 0)
  198.         goto ERROR_EXIT;
  199.  
  200.     fUserInit = TRUE;
  201.                                                     // Set up index block buffer
  202.     memset(gi.pbBlock, 0, gi.usBlockSize);    
  203.     gi.usBlockUsed = 0;
  204.     gi.lBlocks = 0;
  205.     gi.di_index.pbBlock = pbData;
  206.     gi.di_index.cbBlock = usDataBlockSize;
  207.     gi.di_index.pbKey = entry.bKey;
  208.  
  209.     for (i = 0; i < lDataBlocks; ++i)
  210.         {
  211. #if OS_UNIX
  212.         if ((i % 100) == 0)
  213.             Output("  Level 0 Blocks, Data %ld, Index %ld\n", i, gi.lBlocks);
  214. #else
  215.         if ((i % 100) == 0)
  216.             Output("\r  Level 0 Blocks, Data %ld, Index %ld", i, gi.lBlocks);
  217. #endif
  218.                                                     // Read block
  219.         if (!DioReadBlock(hlf, pbData, NULL, NULL))
  220.             goto ERROR_EXIT;
  221.                                                     // Call user to get key
  222.         memset(&entry, 0, sizeof(entry));
  223.         gi.di_index.lBlock = i;
  224.         gi.di_index.cbKey = 0;
  225.         if (!gi.pfnindex(&gi.di_index))
  226.             goto ERROR_EXIT;
  227.                                                     // Validate key
  228.         Assert(gi.di_index.cbKey && gi.di_index.cbKey <= ISAM_KEY_LEN);
  229.         usKeyTotal = (USHORT)(sizeof(entry) - ISAM_KEY_LEN + gi.di_index.cbKey);
  230.         if (gi.usBlockUsed + usKeyTotal > gi.usBlockSize)
  231.             {                                        // Write block if this key won't fit
  232.             if (!DioIndexWrite())
  233.                 goto ERROR_EXIT;
  234.             }
  235.         entry.bSize = (BYTE)gi.di_index.cbKey;
  236.         entry.lBlock = i;
  237.         memcpy(gi.pbBlock + (SIZET)gi.usBlockUsed, &entry, usKeyTotal);
  238.         gi.usBlockUsed += (USHORT)usKeyTotal;
  239.         }
  240.     if (gi.usBlockUsed)                        // Write partial block if any
  241.         {
  242.         if (!DioIndexWrite())
  243.             goto ERROR_EXIT;
  244.         }
  245.     Output("\r  Level 0 Blocks, Data %ld, Index %ld\n", i, gi.lBlocks);
  246.     if (!DioAppendClose(TRUE, TRUE))        // Update data file
  247.         goto ERROR_EXIT;
  248.  
  249.     fResult = TRUE;
  250.  
  251. ERROR_EXIT:
  252.     if (fUserInit)                                // Allow user to clean up
  253.         {
  254.         memset(&gi.di_index, 0, sizeof(gi.di_index));
  255.         gi.di_index.lBlock = ISAM_END;
  256.         if (!gi.pfnindex(&gi.di_index))
  257.             fResult = FALSE;
  258.         }
  259.     if (pbData)                                    // Free buffer
  260.         MemFree(pbData);
  261.     DioCloseLogical(hlf);
  262.     return fResult;
  263. }
  264.  
  265.  
  266.  
  267. //----------------------------------------------------------------------------
  268. //   Description:    Delete existing index files.
  269. //    Parameters:    pcszLogical        Logical file name
  270. //       Returns:    TRUE if successful.
  271. //----------------------------------------------------------------------------
  272. static BOOL FN_L DioIndexDelete(void)
  273. {
  274.     SIZET i;
  275.  
  276.     for (i = 0; i < ISAM_MAX_LEVEL; ++i)
  277.         if (DioIsLogicalFile(gi.pcszLogical, (USHORT)(DFT_ISAM0 + i)))
  278.             {
  279.             if (!DioDelete(HPF2PCSZ(gi.hpf), gi.pcszLogical, (USHORT)(DFT_ISAM0 + i)))
  280.                 return FALSE;
  281.  
  282.             Output("  Deleted existing index level %u\n", i);
  283.             }
  284.     return TRUE;
  285. }
  286.  
  287.  
  288. //----------------------------------------------------------------------------
  289. //   Description:    Index the first level of the isam data file.
  290. //    Parameters:    usLevel                    ISAM level to index
  291. //       Returns:    TRUE if successful.
  292. //----------------------------------------------------------------------------
  293. static BOOL FN_L DioIndexLevel(USHORT usLevel)
  294. {
  295.     HLF hlf;
  296.     USHORT usDataBlockSize;
  297.     LONG i, lDataBlocks;
  298.     PBYTE pbData = NULL;
  299.     PISAMENTRY pentry;
  300.     USHORT usKeyTotal;
  301.     BOOL fResult = FALSE;
  302.  
  303.                                                     // Open logical file
  304.     if (!DioOpenLogical(gi.pcszLogical, &hlf, (USHORT)(DFT_ISAM0 + usLevel - 1)))
  305.         return FALSE;
  306.                                                     // Get block size
  307.     if (!DioGetBlockSize(hlf, &usDataBlockSize))
  308.         goto ERROR_EXIT;
  309.     Assert(usDataBlockSize == gi.usBlockSize);
  310.                                                     // Get number of blocks
  311.     if (!DioGetBlocks(hlf, &lDataBlocks))
  312.         goto ERROR_EXIT;
  313.  
  314.     pbData = MemAlloc((SIZET)usDataBlockSize);
  315.     if (pbData == NULL)
  316.         goto ERROR_EXIT;
  317.  
  318.     Output(
  319.         "Indexing level %u.\n"
  320.         "  Block Size: %u\n"
  321.         "  Total Blocks: %ld\n",
  322.         usLevel,
  323.         usDataBlockSize, lDataBlocks);
  324.  
  325.     pentry = (PISAMENTRY)pbData;
  326.                                                     // Set up to append index
  327.     if (!DioAppend(HPF2PCSZ(gi.hpf), gi.pcszLogical, (USHORT)(DFT_ISAM0 + usLevel),
  328.     gi.usBlockSize, &gi.hf, NULL))
  329.         goto ERROR_EXIT;
  330.  
  331.     gi.fpos = FileGetPos(gi.hf);            // Get file position to append at
  332.     if (gi.fpos < 0)
  333.         goto ERROR_EXIT;
  334.                                                     // Initialize index key buffer
  335.     memset(gi.pbBlock, 0, gi.usBlockSize);
  336.     gi.usBlockUsed = 0;
  337.     gi.lBlocks = 0;
  338.     for (i = 0; i < lDataBlocks; ++i)
  339.         {
  340. #if OS_UNIX
  341.         if ((i % 100) == 0)
  342.             {
  343.             Output("  Level %u Blocks, Data %ld, Index %ld\n",
  344.                 usLevel, i, gi.lBlocks);
  345.             }
  346. #else
  347.         if ((i % 100) == 0)
  348.             {
  349.             Output("\r  Level %u Blocks, Data %ld, Index %ld",
  350.                 usLevel, i, gi.lBlocks);
  351.             }
  352. #endif
  353.  
  354.         if (!DioReadBlock(hlf, pbData, NULL, NULL))
  355.             goto ERROR_EXIT;
  356.  
  357.         usKeyTotal = (USHORT)(sizeof(ISAMENTRY) - ISAM_KEY_LEN + (SIZET)pentry->bSize);
  358.         if (gi.usBlockUsed + usKeyTotal > gi.usBlockSize)
  359.             if (!DioIndexWrite())
  360.                 goto ERROR_EXIT;
  361.         pentry->lBlock = i;
  362.         memcpy(gi.pbBlock + (SIZET)gi.usBlockUsed, pentry, usKeyTotal);
  363.         gi.usBlockUsed += (USHORT)usKeyTotal;
  364.         }
  365.     if (gi.usBlockUsed)                        // Write partial key
  366.         if (!DioIndexWrite())
  367.             goto ERROR_EXIT;
  368.     Output("\r  Level %u Blocks, Data %ld, Index %ld\n",
  369.         usLevel, i, gi.lBlocks);
  370.     if (!DioAppendClose(TRUE, TRUE))
  371.         goto ERROR_EXIT;
  372.     fResult = TRUE;
  373.  
  374. ERROR_EXIT:
  375.     if (pbData)                                    // Free buffer
  376.         MemFree(pbData);
  377.     DioCloseLogical(hlf);
  378.     return fResult;
  379. }
  380.  
  381.  
  382. //----------------------------------------------------------------------------
  383. //   Description:    Write isam data to disk.
  384. //    Parameters:    
  385. //       Returns:    TRUE if successful.
  386. //----------------------------------------------------------------------------
  387. static BOOL FN_L DioIndexWrite(void)
  388. {
  389.     if (!FileWrite(gi.hf, gi.pbBlock, (SIZET)gi.usBlockSize, gi.fpos))
  390.         return FALSE;
  391.  
  392.     gi.lTotalBlocks++;
  393.     gi.lTotalSlack += (LONG)(gi.usBlockSize - gi.usBlockUsed);
  394.     gi.fpos += (FPOS)gi.usBlockSize;
  395.     memset(gi.pbBlock, 0, gi.usBlockSize);
  396.     gi.usBlockUsed = 0;
  397.     if (gi.lBlocks == 0x7FFFFFFFL)
  398.         {
  399.         Error("Maximum number of blocks exceeded.");
  400.         return FALSE;
  401.         }
  402.     gi.lBlocks++;
  403.     return TRUE;
  404. }
  405. //----------------------------------------------------------------------------
  406. //------------------------------- End of File --------------------------------
  407. //----------------------------------------------------------------------------
  408.